<?php

/**
 * Basic Antidetect storage by database
 *
 * Anti Detect login information.
 *
 * PHP versions 5
 * CAKEPHP versions 2.x
 * 
 * Green CMS - Content Management System and Framework Powerfull by Cakephp
 * Copyright 2012, GREEN GLOBAL CO., LTD (toancauxanh.vn)
 * 
 * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @author        Technology Lab No.I <tech1@toancauxanh.vn>
 * @link          
 * @package       Controller.Component.Auth
 * @since         Green v 1.0
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
App::uses('BaseAntidetect', 'Controller/Component/Auth');

class BasicAntidetect extends BaseAntidetect {

    /**
     * Settings for this object.
     *
     * - `count` The maximum number incorrect within an login period of time
     * - `time` The period of time pending
     * - `multiply` exponentially with ip address
     * - `adapter` The model database will storage input,
     *
     * @var array
     */
    public $settings = array(
        'activated' => true,
        'count' => 5,
        'time' => 20,
        'multiply' => 5,
        'adapter' => 'Antidetect',
    );

    /**
     * Garbage collection
     * 
     * Permanently remove all expired and deleted data
     *
     * @return void
     */
    public function gc() {
        $Model = ClassRegistry::init($this->settings['adapter']);
        $Model->deleteAll(array($Model->alias . '.time <' => time()), false, false);
    }

    /**
     * Anti detect a user input.
     *
     * @param Model $User user model
     * @param string $input to be authentication information from.
     * @return boolean true on is secure, false on failure.
     */
    public function antidetect(Model $User, $input) {
        if (!$this->activate()) {
            return true;
        }
        $Model = ClassRegistry::init($this->settings['adapter']);
        $addr = env('REMOTE_ADDR');
        if ($Model->find('count', array(
                    'recursive' => -1,
                    'conditions' => array(
                        $Model->alias . '.time >=' => time(),
                        'or' => array(
                            array(
                                $Model->alias . '.name' => $input,
                                $Model->alias . '.count >=' => $this->settings['count']
                            ),
                            array(
                                $Model->alias . '.name' => $addr,
                                $Model->alias . '.count >=' => $this->settings['count'] * $this->settings['multiply']
                        )))))) {
            $this->_blocked = true;
            return false;
        }
        $this->_blocked = false;
        return true;
    }

    /**
     * Stored a user input incorrect
     *
     * @param Model $User user model
     * @param string $input to be authentication information from.
     * @return void
     */
    public function add(Model $User, $input) {
        if (!$this->activate()) {
            return;
        }

        $this->gc();
        $Model = ClassRegistry::init($this->settings['adapter']);

        foreach (array($input, env('REMOTE_ADDR')) as $value) {
            $data = array('name' => $value);
            $lastData = $Model->find('first', array('recursive' => -1, 'conditions' => $data));

            $count = 1;

            if (!$lastData) {
                $Model->create();
            } else {
                $Model->id = $lastData[$Model->alias][$Model->primaryKey];
                $count = $lastData[$Model->alias]['count'] + 1;
            }
            $Model->save(array_merge($data, array('count' => $count, 'time' => time() + ($this->settings['time'] * MINUTE))));
        }
    }

    /**
     * Remove a user input incorrect has stored
     *
     * @param Model $User user model
     * @param string $input to be authentication information from.
     * @return void
     */
    public function remove(Model $User, $input) {
        if (!$this->activate()) {
            return;
        }
        $Model = ClassRegistry::init($this->settings['adapter']);
        $Model->deleteAll(array($Model->alias . '.name' => $input), false, false);
    }

}
